package com.rz.htk.order.service.impl;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.houbb.opencc4j.util.ZhConverterUtil;
import com.rz.core.exception.GlobalException;
import com.rz.core.kit.RedisKit;
import com.rz.core.resp.ResultResp;
import com.rz.htk.central.entity.CentralPlace;
import com.rz.htk.central.service.ICentralPlaceService;
import com.rz.htk.config.RedisKeyConfig;
import com.rz.htk.destination.entity.Destination;
import com.rz.htk.destination.service.IDestinationService;
import com.rz.htk.dubbo.service.AdminService;
import com.rz.htk.dubbo.service.DictDataService;
import com.rz.htk.message.entity.Message;
import com.rz.htk.message.service.IMessageService;
import com.rz.htk.order.entity.*;
import com.rz.htk.order.entity.excel.CountOrder;
import com.rz.htk.order.entity.excel.OrderExcelModel;
import com.rz.htk.order.entity.excel.OrderExcelModelUSA;
import com.rz.htk.order.entity.vo.OrderDeleteParam;
import com.rz.htk.order.entity.vo.OrderTrackParam;
import com.rz.htk.order.entity.vo.PrintParam;
import com.rz.htk.order.listeners.OrderImportListener;
import com.rz.htk.order.listeners.OrderImportListenerUSA;
import com.rz.htk.order.mapper.OrderMapper;
import com.rz.htk.order.mapper.OrderTrackMapper;
import com.rz.htk.order.service.*;
import com.rz.htk.order.task.ChinaPostTask;
import com.rz.htk.order.task.USAPDFTask;
import com.rz.htk.postal.service.IExpressCodeService;
import com.rz.htk.print.entity.PrintTempField;
import com.rz.htk.print.entity.PrintTemplate;
import com.rz.htk.print.model.TempField;
import com.rz.htk.print.service.IPrintTempFieldService;
import com.rz.htk.print.service.IPrintTemplateService;
import com.rz.htk.print.util.PDFUtil;
import com.rz.htk.print.util.PrintPdfUtil;
import com.rz.htk.print.util.QrCodeUtil;
import com.rz.htk.product.entity.Product;
import com.rz.htk.product.entity.ProductPrice;
import com.rz.htk.product.service.IProductPriceService;
import com.rz.htk.product.service.IProductService;
import com.rz.htk.sys.entity.StateCode;
import com.rz.htk.sys.service.IStateCodeService;
import com.rz.htk.template.entity.vo.ExportParam;
import com.rz.htk.template.service.ExportService;
import com.rz.htk.type.OrderState;
import consumer.model.SysDictData;
import consumer.model.Zone;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.io.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    private Logger log = LoggerFactory.getLogger("OrderServiceImpl");

    @Resource
    private CommodityService commodityService;
    @Resource
    private IProductPriceService productPriceService;
    @Resource
    private IExpressCodeService expressCodeService;
    @Resource
    private RedisKit redisKit;
    @Resource
    private USAPDFTask usapdfTask;
    @Resource
    private AdminService adminService;
    @Resource
    private IOrderRecordService orderRecordService;
    @Resource
    private IProductService iProductService;
    @Resource
    private DictDataService dictDataService;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private OrderTrackMapper trackMapper;
    @Resource
    private ExportService exportService;
    @Resource
    private IMessageService iMessageService;
    @Resource
    private IOrderHisService iOrderHisService;
    @Resource
    private PrintPdfUtil printPdfUtil;
    @Resource
    private IOrderTrackService orderTrackService;
    @Resource
    private ICentralPlaceService centralPlaceService;
    @Resource
    private ChinaPostTask chinaPostTask;
    @Resource
    private IPrintTempFieldService printTempFieldService;
    @Resource
    private IPrintTemplateService printTemplateService;
    @Resource
    private IDestinationService destinationService;
    @Resource
    private IUSPSValidate iuspsValidate;
    @Resource
    private PdfService pdfService;
    @Resource
    private IStateCodeService stateCodeService;

    private static List<CentralPlace> centralPlaceList = new ArrayList<>();

    @PostConstruct
    public void initCenterPlace(){
        centralPlaceList = centralPlaceService.list();
    }

    @Override
    public IPage<Order> getPage(Order order) {
        QueryWrapper<Order> wrapper = buildWrapper(order);
        wrapper.orderByDesc("id");
        Page<Order> page = new Page<>(order.getPageNo(), order.getPageSize());
        IPage<Order> desktopIPage = page(page, wrapper);
        buildRecord(desktopIPage.getRecords());
        return desktopIPage;
    }

    @Override
    public void exportOrder(Order order, OutputStream out) {
        QueryWrapper<Order> wrapper = buildWrapper(order);
        wrapper.orderByAsc("id");
        List<Order> orders = list(wrapper);
        orders =  buildExportOrderList(orders, order);
        exportService.export(order.getPrdCode(), orders, out);
    }

    @Async
    public void asynprocessUSA(Order order) throws Exception {
        usapdfTask.processUSA(order);
    }

    @Override
    public int updateTrackSuccess(String afterCode) {
        return orderMapper.updateTrackSuccess(afterCode);
    }

    @Override
    public int updatePushYousuSuccess(String afterCode) {
        return orderMapper.updatePushYousuSuccess(afterCode);
    }

    @Override
    public void getByOrderIds(List<Integer> orderIds, OutputStream output) {
        List<Order> orders = new ArrayList<>(listByIds(orderIds));
        buildRecord(orders);
        printPdfUtil.createPdf(orders, output);
    }


    @Override
    public void rightCenteralPlace() {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("prd_code", "HTK_P0010");
        queryWrapper.eq("verify_state", 0);
        queryWrapper.orderByDesc("id");
        List<Order> orderList = list(queryWrapper);
        List<Order> newOrderList = new ArrayList<>();
        orderList.forEach(order -> {
            String address = order.getRecipientsAddress();
            address = address.trim().replaceAll(" ", "");
            String simpleAddress = ZhConverterUtil.convertToSimple(address);
            CentralPlace cp = getEsAddress(simpleAddress);
            if(cp!=null){
                order.setSsid("14");
                order.setSsna("八里");
                order.setSsno("6118");
                order.setEsid(cp.getEsid());
                order.setEsno(cp.getEsno());
                order.setEsna(cp.getStationName());
                order.setVerifyState(1);
                newOrderList.add(order);
            }
        });
        if (newOrderList.size() > 0) {
            boolean isok = updateBatchById(newOrderList, 100);
            if (isok) {
                newOrderList.clear();
            }
        }
    }

    private CentralPlace getEsAddress(String address){
        CentralPlace cp = null;
        for (int i = 0,j=centralPlaceList.size(); i < j; i++) {
            CentralPlace centralPlace = centralPlaceList.get(i);
            String simpleCityName = centralPlace.getSimpleCityName().trim().replaceAll(" ","");
            String simpleAreaName = centralPlace.getSimpleAreaName().trim().replaceAll(" ","");
            simpleCityName = ZhConverterUtil.convertToSimple(simpleCityName);
            simpleAreaName = ZhConverterUtil.convertToSimple(simpleAreaName);
            if(address.contains(simpleCityName) && address.contains(simpleAreaName)){
                cp = centralPlace;
                break;
            }
        }
        return cp;
    }

    @Override
    public IPage<Order> getSimplePage(Order order) {
        QueryWrapper<Order> wrapper = buildWrapper(order);
        wrapper.orderByDesc("id");
        Page<Order> page = new Page<>(order.getPageNo(), order.getPageSize());
        IPage<Order> desktopIPage = page(page, wrapper);
        buildSimpleRecord(desktopIPage.getRecords());
        return desktopIPage;
    }

    @Override
    public Order getOrderByAfterCode(String afterCode) {
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.eq("after_code", afterCode);
        Order order  = getOne(wrapper);
        buildIntoOutRecord(order);
        return order;
    }

    private void buildIntoOutRecord(Order order) {
        if(order==null){
            return;
        }
        Integer tranid = order.getTransportation();
        Product product = iProductService.getProductByCode(order.getPrdCode());
        ProductPrice productPrice = productPriceService.getById(tranid);
        if (productPrice != null) {
            String priceName = productPriceService.getProductPriceName(product,productPrice);
            order.setTransportationName(priceName);
        } else {
            order.setTransportationName(product.getPrdName() + "_" + order.getDestination());
        }
    }

    @Async
    public void asyncOrderReceiveBack(Integer orderId) throws Exception {
        orderReceiveBack(orderId);
    }

    @Override
    public Order orderReceiveBack(Integer orderId) throws Exception {
        Order order = getById(orderId);
        List<Order> orders = new ArrayList<>();
        orders.add(order);
        buildRecord(orders);
        String afterCode = chinaPostTask.orderReceiveBack(order);
        if(!StringUtils.isEmpty(afterCode)){
            order.setAfterCode(afterCode);
            updateById(order);
        }
        return order;
    }

    @Override
    public void downloadTemplateByOrder(List<Integer> orderIds, ServletOutputStream outputStream) {
        List<Order> orders = new ArrayList<>(listByIds(orderIds));
        try {
            chinaPostTask.downloadTemplateByOrder(orders,outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void downloadTemplateByAfterCode(List<String> afterCodes, ServletOutputStream outputStream) {
        try {
            chinaPostTask.downloadTemplateByAfterCode(afterCodes,outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean syncOrderTrack(OrderTrackParam param) {
        if(StringUtils.isEmpty(param.getExpressCode())){
            throw new GlobalException("转运单号不能为空");
        }
        if(param.getTrackList()==null || param.getTrackList().size()==0){
            throw new GlobalException("轨迹列表不能为空");
        }
        param.getTrackList().forEach(orderTrack -> {
            if(StringUtils.isEmpty(orderTrack.getScanDate())){
                throw new GlobalException("轨迹中扫描时间不能为空");
            }
            if(StringUtils.isEmpty(orderTrack.getScanAddr())){
                throw new GlobalException("轨迹中扫描地点或站点名称不能为空");
            }
            orderTrack.setAfterCode(param.getExpressCode());
        });
        Order order = getOrderByAfterCode(param.getExpressCode());
        if(order==null){
            throw new GlobalException("转运单号"+param.getExpressCode()+"在系统中不存在，请确认！");
        }
        trackMapper.deleteByAfterCode(param.getExpressCode());
        boolean success = orderTrackService.saveBatch(param.getTrackList());
        return success;
    }

    /**
     * 导出报关单
     * @param param
     * @param out
     */
    @Override
    public void exportCustomsDeclaration(ExportParam param, OutputStream out) {
        List<Order> orderList = new ArrayList<>(listByIds(param.getIds()));
        Product product = iProductService.getProductByCode(param.getPrdCode());
        if (product == null) {
            throw new GlobalException("产品“" + param.getPrdCode() + "”不存在！");
        }
        if (product.getCustomsClearanceTemplate() == null) {
            throw new GlobalException("产品“" + param.getPrdCode() + "”没有定义报关单模板！");
        }
        exportService.export(orderList, product.getCustomsClearanceTemplate(), out);
    }

    public List<String> sToList(String code){
        code =code.replaceAll("，",",");
        String s[] = code.split(",");
        if(s.length>0){
            for(int i = 0;i<s.length;i++){
                if(s[i].length()==30){
                    s[i] = s[i].substring(8);
                }
            }
        }
        return Arrays.asList(s);
    }

    private QueryWrapper<Order> buildWrapper(Order order) {
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(order.getCommodityCode())) {
            wrapper.in("commodity_code", sToList(order.getCommodityCode()));
        }
        if (StringUtils.isNotEmpty(order.getAfterCode())) {
            wrapper.in("after_code", sToList(order.getAfterCode()));
        }
        if (StringUtils.isNotEmpty(order.getPrdCode())) {
            wrapper.eq("prd_code", order.getPrdCode());
        }
        if (order.getState() != null && order.getState() > 0) {
            wrapper.eq("state", order.getState());
        }
        if (order.getRmkState() != null && order.getRmkState() > 0) {
            wrapper.eq("rmk_state", order.getRmkState());
        }
        if (StringUtils.isNotEmpty(order.getDestination())) {
            wrapper.like("destination", order.getDestination());
        }
        if (StringUtils.isNotEmpty(order.getRecipientsName())) {
            wrapper.like("recipients_name", order.getRecipientsName());
        }
        if (StringUtils.isNotEmpty(order.getRecipientsCompany())) {
            wrapper.like("recipients_company", order.getRecipientsCompany());
        }
        if (StringUtils.isNotEmpty(order.getRecipientsAddress())) {
            wrapper.like("recipients_address", order.getRecipientsAddress());
        }
        if (StringUtils.isNotEmpty(order.getRecipientsIdNumber())) {
            wrapper.like("recipients_id_number", order.getRecipientsIdNumber());
        }
        if (StringUtils.isNotEmpty(order.getRecipientsPhone())) {
            wrapper.like("recipients_phone", order.getRecipientsPhone());
        }
        if (StringUtils.isNotEmpty(order.getCommodityName())) {
            wrapper.like("commodity_name", order.getCommodityName());
        }
        if (StringUtils.isNotEmpty(order.getSenderCompany())) {
            wrapper.like("sender_company", order.getSenderCompany());
        }
        if (StringUtils.isNotEmpty(order.getSenderIdNumber())) {
            wrapper.like("sender_id_number", order.getSenderIdNumber());
        }
        if (StringUtils.isNotEmpty(order.getSenderName())) {
            wrapper.like("sender_name", order.getSenderName());
        }
        if (StringUtils.isNotEmpty(order.getSenderPhone())) {
            wrapper.like("sender_phone", order.getSenderPhone());
        }
        if (StringUtils.isNotEmpty(order.getSenderAddress())) {
            wrapper.like("sender_address", order.getSenderAddress());
        }
        if (StringUtils.isNotEmpty(order.getConsumerCode())) {
            wrapper.eq("consumer_code", order.getConsumerCode());
        }
        if (order.getRmkState() != null) {
            wrapper.eq("rmk_state", order.getRmkState());
        }
        //小于
        if (StringUtils.isNotEmpty(order.getEndTime())) {
            wrapper.lt("creation_time", order.getEndTime());
        }
        //大于
        if (StringUtils.isNotEmpty(order.getStartTime())) {
            wrapper.gt("creation_time", order.getStartTime());
        }
        List<Integer> mngID = adminService.getChildrenIds(order.getCrteMngId());
        mngID.add(order.getCrteMngId());
        wrapper.in("crte_mng_id", mngID);

        return wrapper;
    }

    private void buildSimpleRecord(List<Order> orders) {
        if (orders.size() == 0) {
            return;
        }
        List<String> afterCodes = new ArrayList<>();
        orders.forEach(order -> {
            afterCodes.add(order.getAfterCode());
        });
        List<OrderTrack> orderTracks = orderTrackService.getByAfterCodes(afterCodes);
        if (orderTracks.size() > 0) {
            orders.forEach(order -> {
                List<OrderTrack> orderTrackList = orderTracks.stream().filter(orderTrack -> orderTrack.getAfterCode().equals(order.getAfterCode())).collect(Collectors.toList());
                if (orderTrackList.size() > 0) {
                    order.setTrackStrs(orderTrackList.get(0).getScanDate() + " " + orderTrackList.get(0).getScanAddr() + " " + orderTrackList.get(0).getScanInfo());
                }
            });
        }
    }

    private void buildRecord(List<Order> orders) {
        if (orders.size() == 0) {
            return;
        }
        List<String> orderCodes = new ArrayList<>();
        List<String> afterCodes = new ArrayList<>();
        List<Integer> luxiangIds = new ArrayList<>();
        Map<String, Product> productMap = new HashMap<>();
        orders.forEach(order -> {
            orderCodes.add(order.getCommodityCode());
            luxiangIds.add(order.getTransportation());
            afterCodes.add(order.getAfterCode());
            if(!StringUtils.isEmpty(order.getAfterCode())){
                order.setAfterCode4(order.getAfterCode().substring(order.getAfterCode().length()-4));
                try {
                    InputStream is = QrCodeUtil.createQrcodeImage(order.getAfterCode());
                    order.setAfterCodeQrCode(QrCodeUtil.getImageStr(is));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                order.setAfterCodeTxt("出货单号："+order.getAfterCode());
            }
            if(!StringUtils.isEmpty(order.getTimes())){
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                String dateTime = order.getCreationTime().format(formatter);
                order.setTimesStr("日期："+dateTime+"序号：1");
            }
        });
        List<Commodity> commodities = commodityService.getListCommodityBycodes(orderCodes);
        List<ProductPrice> priceList = (List<ProductPrice>) this.productPriceService.listByIds(luxiangIds);
        Map<Integer, ProductPrice> priceMap = new HashMap<>();
        for (ProductPrice price : priceList) {
            priceMap.put(price.getId(), price);
        }
        List<OrderTrack> orderTracks = orderTrackService.getByAfterCodes(afterCodes);
        orders.forEach(order -> {
            int amount = 0;
            double totalPrices = 0.00;
            List<Commodity> commodityList = commodities.stream().filter(commodity -> commodity.getCommodityCode().equals(order.getCommodityCode())).collect(Collectors.toList());
            order.setCommodityList(commodityList);
            StringBuilder sb = new StringBuilder();
            StringBuilder nameSb = new StringBuilder();
            for (int i = 0; i < commodityList.size(); i++) {
                Commodity commodity = commodityList.get(i);
                if(commodity.getCommodityValue()!=null && commodity.getAmount()!=null){
                    amount += commodity.getAmount();
                    totalPrices += commodity.getCommodityValue() * commodity.getAmount();
                }
                nameSb.append(commodity.getCommodityName()).append("，");
                sb.append(commodity.getCommodityName()).append("，").append(commodity.getAmount()).append("，").append(commodity.getCommodityValue());
            }
            order.setCommodityName(nameSb.toString());
            order.setCommodityDesc(sb.toString());
            order.setAmount(amount);
            order.setPrice(totalPrices);

            List<Pdf> pdfList = pdfService.getPdfBycode(order.getCommodityCode());
            if(CollectionUtils.isNotEmpty(pdfList)){
             Pdf pdf = pdfList.get(0);
             order.setUSARmk(pdf.getRmk());
            }
            if (!productMap.containsKey(order.getPrdCode())) {
                Product product = this.iProductService.getProductByCode(order.getPrdCode());
                productMap.put(order.getPrdCode(), product);
            }
            order.setTransportationName(priceMap.get(order.getTransportation()) == null ? "" :
                    this.productPriceService.getProductPriceName(productMap.get(order.getPrdCode()), priceMap.get(order.getTransportation())));
            if (orderTracks.size() > 0) {
                List<OrderTrack> orderTrackList = orderTracks.stream().filter(orderTrack -> orderTrack.getAfterCode().equals(order.getAfterCode())).collect(Collectors.toList());
                order.setOrderTracks(orderTrackList.size() == 0 ? new ArrayList<>() : orderTrackList);
                StringBuilder trackSb = new StringBuilder();
                if (orderTrackList.size() > 0) {
                    orderTrackList.forEach(orderTrack -> trackSb.append(orderTrack.getScanDate()).append(" ")
                            .append(orderTrack.getScanAddr()).append(" ")
                            .append(orderTrack.getScanInfo()).append(" \n "));
                    order.setTrackStrs(trackSb.toString());
                }
            }
        });
    }

    public List<Order> listOrderByCode(String code) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("commodity_code", code);
        return list(queryWrapper);
    }

    public List<Order> listOrderByAfterCode(String code) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("after_code", code);
        return list(queryWrapper);
    }

    @Transactional
    public boolean saveOrder(Order order) {

        Product product = iProductService.getProductByCode(order.getPrdCode());
//        ProductPrice productPrice = productPriceService.getById(order.getTransportation());
//        if ((productPrice.getMaxWeight() > 0 && order.getWeight() > productPrice.getMaxWeight()) || (productPrice.getMinWeight() > 0 && order.getWeight() < productPrice.getMinWeight())) {
//            throw new GlobalException("订单重量不在产品重量范围内，请重新选择产品或确认重量");
//        }

        if (order.getId() == null) {
            if (CollectionUtils.isNotEmpty(this.listOrderByCode(order.getCommodityCode()))) {
                throw new GlobalException("订单编号【" + order.getCommodityCode() + "】已存在！");
            }
            if (CollectionUtils.isNotEmpty(this.listOrderByAfterCode(order.getAfterCode()))) {
                throw new GlobalException("转单号【" + order.getAfterCode() + "】已存在！");
            }
            if(order.getPrdCode().equals("HTK_P0022") || order.getPrdCode().equals("HTK_P0023")) {
                // 发往美国usps的订单，需要进行usps的订单内容校验
                this.iuspsValidate.validate(order);
            }
            if (StringUtils.isEmpty(order.getCommodityCode())) {
                int hashCodeV = UUID.randomUUID().toString().hashCode();
                if (hashCodeV < 0) {
                    hashCodeV = -hashCodeV;
                }
                String aCode = "HTK" + String.format("%010d", hashCodeV);
                order.setCommodityCode(aCode);
            }
            //如果转运单号是空的，并且产品不是邮政的，才去获取转运单号
            if (StringUtils.isEmpty(order.getAfterCode())) {
                if (!"001".equals(order.getPrdCode()) && !"005".equals(order.getPrdCode()) && !"018".equals(order.getPrdCode())) {
                    order.setAfterCode(expressCodeService.getExpressCode(product.getPrdCode(), product.getExpressType()));
                }
            }
            if (order.getTransportation() != null) {
                // 只有路线存在的情况下，才计算价格.20190902
                order.setTotalPrices(productPriceService.quote(order));
            }

            order.setCreationTime(LocalDateTime.now());
            order.setState(OrderState.dairuku);
            order.setDelFlag(0);
        }
        order.setPrdCode(order.getPrdCode());
        if(order.getRoughWeight()!=null&&order.getRoughWeight()>0) {
            order.setNetWeight(order.getRoughWeight() - order.getWeight());
        }
        SysDictData dictData = dictDataService.getByCode("unit_" + product.getUnit());
        if (dictData != null) {
            order.setUnit(dictData.getDictdataName());
        }
        // 如果订单没有“资费标准/路向”信息，则系统自动选择一个最优资费标准
        ProductPrice bestProductPrice = null;
        if (order.getTransportation() == null || order.getTransportation() == 0) {
            bestProductPrice = productPriceService.getBestProductPrice(order);
            if (bestProductPrice != null) {
                order.setTransportation(bestProductPrice.getId());
            } else {
                throw new GlobalException("系统没有为订单匹配到适用的资费标准！");
            }
        } else {
            bestProductPrice = this.productPriceService.getById(order.getTransportation());
        }

        boolean isOk = this.saveOrUpdate(order);
        if (!isOk) {
            throw new GlobalException("订单信息保存失败！");
        } else {
            if (CollectionUtils.isNotEmpty(order.getCommodityList())) {
                for (int i = 0; i < order.getCommodityList().size(); i++) {
                    Commodity commodity = order.getCommodityList().get(i);
                    commodity.setCommodityCode(order.getCommodityCode());
                    commodity.setCreationTime(LocalDateTime.now());
                    commodityService.saveCommodity(commodity);
                }
            }

            orderRecordService.savaRecord(order.getCommodityCode(), order.getState(), order.getCrteMngId(), "");
        }
        redisKit.putHash(RedisKeyConfig.ORDER_CODE, order.getCommodityCode(), order.getCommodityCode());
        if(order.getPrdCode().equals("001") || order.getPrdCode().equals("005") || order.getPrdCode().equals("018")){
            try {
                asyncOrderReceiveBack(order.getId());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // 入库称重后，走下面的逻辑
        if (order.getState().equals(15)) {
            if(order.getPrdCode().equals("HTK_P0022") || order.getPrdCode().equals("HTK_P0023")){
                try {
                    // 发件人信息改为目的港信息
                    // 入库后重新获取订单资费标准8
                    bestProductPrice = productPriceService.getBestProductPrice(order);
                    if (bestProductPrice != null) {
                        Zone zone =  productPriceService.selectBestZone(order);
                        Destination destination = destinationService.getDestination(order.getDestination(), zone.getZip());
                        if (destination != null) {
                            order.setSenderPostcode(destination.getZip());
                            order.setSenderAddress(destination.getAddress());
                            order.setSenderName(destination.getManager());
                            order.setSenderPhone(destination.getPhone());
                            order.setSenderCompany(destination.getCompany());
                            order.setSenderProvince(destination.getProvince());
                            order.setSenderCity(destination.getCity());

                            // 如果订单中的州信息不是简写，要转成简写
                            String province = order.getProvince();
                            if (province != null && province.length() != 2) {
                                StateCode stateCode = stateCodeService.getByName(province, order.getDestination());
                                if (stateCode != null) {
                                    order.setProvince(stateCode.getStateSimple());
                                }
                            }
                        }
                    } else {
                        throw new GlobalException("USPS产品订单没有找到适用的资费标准！");
                    }
                    order.setWidth(order.getWidth() == null ? "0" : order.getWidth());
                    order.setLongs(order.getLongs() == null ? "0" : order.getLongs());
                    order.setHigh(order.getHigh() == null ? "0" : order.getHigh());
                    asynprocessUSA(order);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }

        return true;
    }

    @Transactional
    public ResultResp saveOrderGetCode(Order order) {
        String result = "";
        String afterCode = "";
        ResultResp resultResp = new ResultResp();
        int hashCodeV = UUID.randomUUID().toString().hashCode();
        if (hashCodeV < 0) {
            hashCodeV = -hashCodeV;
        }
        String aCode = "HTK" + String.format("%010d", hashCodeV);
        if (StringUtils.isEmpty(order.getCommodityCode())) {
            order.setCommodityCode(aCode);
        }
        if (StringUtils.isEmpty(order.getDestination())) {
            result += "目的地不能为空！";
        }
        if (order.getWeight() <= 0) {
            result += "重量不能为空！";
        }
        if (StringUtils.isEmpty(order.getRecipientsName())) {
            result += "收件人姓名不能为空！";
        }
        if (StringUtils.isEmpty(order.getRecipientsAddress())) {
            result += "收件人地址不能为空！";
        }
        if (StringUtils.isEmpty(order.getRecipientsPhone())) {
            result += "收件人电话不能为空！";
        }
        if (StringUtils.isEmpty(order.getSenderPhone())) {
            result += "发件人电话不能为空！";
        }
        if (StringUtils.isEmpty(order.getSenderAddress())) {
            result += "发件人地址不能为空！";
        }
        if (StringUtils.isEmpty(order.getSenderName())) {
            result += "发件人姓名不能为空！";
        }
        if (StringUtils.isEmpty(order.getPrdCode())) {
            result += "产品编码不能为空！";
        } else {
            // 20190902，订单添加时不选择“路线”，改为选择“产品”
//            List<ProductPrice> priceList = productPriceService.getDestination(order.getPrdCode(), order.getDestination());
//            if (priceList != null && priceList.size() > 0) {
//                order.setTransportation(priceList.get(0).getId());
//            } else {
//                result += "未根据目的地国家，产品编码找到路线！";
//            }
        }
        if (order.getPrdCode().equals("HTK_P0022") || order.getPrdCode().equals("HTK_P0023")) {
            // 针对美国国内usps的产品进行订单内容校验
            iuspsValidate.validate(order);
        }
        if (result != "") {
            resultResp.setCode(1);
            resultResp.setMsg(result);
            resultResp.setData(null);
            return resultResp;
        }
        if (CollectionUtils.isNotEmpty(this.listOrderByCode(order.getCommodityCode()))) {
            resultResp.setCode(1);
            resultResp.setMsg("订单编号【" + order.getCommodityCode() + "】已存在！");
            resultResp.setData(null);
            return resultResp;
        }
        order.setDsk(order.getDsk() == null ? 0 : order.getDsk());
        order.setTimes(LocalDateTime.now().toString());
        order.setCreationTime(LocalDateTime.now());
        order.setState(OrderState.dairuku);
        order.setDelFlag(0);
        //order.setTotalPrices(productPriceService.quote(order));
        //ProductPrice productPrice = productPriceService.getById(order.getTransportation());
        Product product = iProductService.getProductByCode(order.getPrdCode());
        order.setPrdCode(order.getPrdCode());
        afterCode = this.expressCodeService.getExpressCode(product.getPrdCode(), product.getExpressType());
        order.setAfterCode(afterCode);
        SysDictData dictData = dictDataService.getByCode("unit_" + product.getUnit());
        if (dictData != null) {
            order.setUnit(dictData.getDictdataName());
        }
        boolean isOk = this.saveOrUpdate(order);
        if (!isOk) {
            resultResp.setCode(0);
            resultResp.setMsg("订单信息保存失败！");
            resultResp.setData(null);
        } else {
            if (CollectionUtils.isNotEmpty(order.getCommodityList())) {
                for (int i = 0; i < order.getCommodityList().size(); i++) {
                    Commodity commodity = order.getCommodityList().get(i);
                    commodity.setCommodityCode(order.getCommodityCode());
                    commodity.setCreationTime(LocalDateTime.now());
                    commodityService.saveCommodity(commodity);
                }
                orderRecordService.savaRecord(order.getCommodityCode(), order.getState(), order.getCrteMngId(), "");
            }
            redisKit.putHash(RedisKeyConfig.ORDER_CODE, order.getCommodityCode(), order.getCommodityCode());

            String courierReceipt = "";
            try {
                List<Order> orders = new ArrayList<>();
                orders.add(order);
                buildOrderInfo(orders);
                OutputStream outputStream = new ByteArrayOutputStream();
                PDFUtil.createPdf(outputStream,orders.get(0),true);
                ByteArrayInputStream swapStream = printPdfUtil.parse(outputStream);
                courierReceipt = PrintPdfUtil.PDFToBase64(swapStream);
            } catch (Exception e){
                log.error(e.getMessage(), e);
                e.printStackTrace();
            }
            JSONObject json = new JSONObject();
            json.put("commodityCode", order.getCommodityCode());
            json.put("afterCode", afterCode);
            json.put("courierReceipt", courierReceipt);
            resultResp.setCode(1);
            resultResp.setMsg("操作成功");
            resultResp.setData(json);
        }
        return resultResp;
    }

    /**
     * 根据重量产品ID计算单件商品的价格
     *
     * @param weight,id
     * @return
     */
    public double getProductPriceByID(double weight, int id) {
        double price;
        ProductPrice p = productPriceService.getById(id);
        if (weight <= p.getStartingWeight()) {
            price = p.getCertificationFee() + p.getCoverCharge() + p.getStartingPrice();
        } else {
            price = Math.ceil((weight - p.getStartingWeight()) / p.getRate()) * p.getRatePrice() + p.getCertificationFee() + p.getCoverCharge() + p.getStartingPrice();
        }
        return price;
    }


    @Override
    @Transactional
    public boolean batchDelete(OrderDeleteParam deleteParam) {
        deleteParam.getIds().forEach(id -> {
            Order order = this.getById(id);
            if (order != null) {
                boolean isOk = this.removeById(order.getId());
                commodityService.deleteByCode(order.getCommodityCode());
                iOrderHisService.saveOrderHis(order,order.getCrteMngId(),order.getState());
                if (!isOk) {
                    throw new GlobalException("订单 【" + order.getCommodityCode() + "】 信息删除失败！");
                } else {
                    redisKit.deleteHash(RedisKeyConfig.ORDER_CODE, order.getCommodityCode());
                }
            } else {
                throw new GlobalException("订单信息不存在，删除失败！");
            }
        });
        return true;
    }

    @Override
    @Transactional
    public boolean saveOrderMessage(OrderDeleteParam deleteParam) {
        deleteParam.getIds().forEach(id -> {
            Order order = this.getById(id);
            if (order != null) {
                Message message =new Message();
                message.setTitle(deleteParam.getTitle());
                message.setRmk(deleteParam.getMessageRmk());
                message.setCrteMngId(deleteParam.getCrteMngId());
                saveOrderMessage(message,order);
            } else {
                throw new GlobalException("订单信息不存在，删除失败！");
            }
        });

        return true;
    }

    /**
     * 修改订单状态
     *
     * @param deleteParam
     * @return
     */
    @Override
    @Transactional
    public boolean updateOrderState(OrderDeleteParam deleteParam) {
        deleteParam.getIds().forEach(id -> {
            Order order = this.getById(id);
            if (order != null) {
                if((deleteParam.getState()==50) || (deleteParam.getState()==55) || (deleteParam.getState()==31) || (deleteParam.getState()==46)){
                    boolean isOk = iOrderHisService.saveOrderHis(order,deleteParam.getCrteMngId(),deleteParam.getState());
                    if(isOk) {
                        orderRecordService.savaRecord(order.getCommodityCode(),deleteParam.getState(),deleteParam.getCrteMngId(),"");
                        this.removeById(order.getId());
                    }else{
                        throw new GlobalException("订单 【" + order.getCommodityCode() + "】 信息修改失败！");
                    }
                }else{
                    order.setState(deleteParam.getState());
                    boolean isOk = this.updateById(order);
                    if (!isOk) {
                        throw new GlobalException("订单 【" + order.getCommodityCode() + "】 信息修改失败！");
                    }{
                        orderRecordService.savaRecord(order.getCommodityCode(),deleteParam.getState(),deleteParam.getCrteMngId(),"");
                    }
                }
            } else {
                throw new GlobalException("订单信息不存在，修改失败！");
            }
        });
        return true;
    }

    @Override
    @Transactional
    public boolean saveOrderMessage(Message message, Order order) {
        message.setCreationTime(LocalDateTime.now());
        message.setState(0);
        message.setType(1);
        message.setDelFlag(0);
        message.setCommodityCode(order.getCommodityCode());
        message.setOrderId(order.getId());
        message.setCrteOrderId(order.getCrteMngId());
        boolean isOk = iMessageService.saveOrUpdate(message);
        if (!isOk) {
            throw new GlobalException("消息添加失败！");
        } else {
            order.setRmkState(1);
            saveOrder(order);
        }
        return true;
    }

    @Override
    public int updateOrderStateByAfterCode(String afterCode, Integer status) {
        return orderMapper.updateOrderStateByAfterCode(afterCode,status);
    }
    @Override
    public  int udapteOrderAfterCode( String commodityCode,String afterCode){
        return orderMapper.udapteOrderAfterCode(commodityCode,afterCode);
    }
    @Override
    public boolean updateOrderOut(OrderDeleteParam deleteParam) {
        deleteParam.getIds().forEach(id -> {
            Order order = this.getById(id);
            if(deleteParam.getOutWeight()!=null && deleteParam.getOutWeight().compareTo(BigDecimal.ZERO) > 0){
                order.setRoughWeight(deleteParam.getOutWeight().doubleValue());
            }
            order.setState(deleteParam.getState());
            updateById(order);
        });
        return true;
    }

    @Override
    public Collection<Order> print(PrintParam printParam) {
        if(null==printParam.getOrderIds() || printParam.getOrderIds().size() == 0){
            return new ArrayList<>();
        }
        Collection<Order> orders = listByIds(printParam.getOrderIds());
        buildOrderInfo(new ArrayList<>(orders));
        return orders;
    }

    @Override
    public List<Order> exportPdfByHtml(List<String> orderCodes) {
        List<Order> orders = getByAfterCodes(orderCodes);
        buildOrderInfo(orders);
        return orders;
    }


    private ArrayList prdCodes = new ArrayList(){{
        add("HTK_P0022");
        add("HTK_P0023");
    }};
    private void buildOrderInfo(List<Order> orders){
        Set<String> prdCodes = new HashSet<>();
        List<Integer> orderIds = new ArrayList<>();
        orders.forEach(order -> {
            prdCodes.add(order.getPrdCode());
            if(prdCodes.contains(order.getPrdCode())){
                orderIds.add(order.getId());
            }
        });
        if(orderIds.size() > 0){
            List<Pdf> pdfs = pdfService.getPdfByOrderIds(orderIds);
            orders.forEach(order -> pdfs.forEach(pdf -> {
                if(order.getId().equals(pdf.getOrderId())){
                    order.setPdfStr(pdf.getPdf());
                }
            }));
        }
        List<Product> products = iProductService.listProductByCodes(new ArrayList<>(prdCodes));
        Set<Integer> printTempIds = new HashSet<>();
        products.forEach(product -> {
            if(product.getExpressTemplate()!=null && product.getExpressTemplate() > 0){
                printTempIds.add(product.getExpressTemplate());
            }
        });
        if(printTempIds.size() > 0){
            Collection<PrintTemplate> printTemplates = printTemplateService.listByIds(new ArrayList<>(printTempIds));
            List<PrintTempField> fields = printTempFieldService.getFields(new ArrayList<>(printTempIds));
            buildPrintTemps(orders,products,printTemplates,fields);
        }
    }

    private void buildPrintTemps(Collection<Order> orders,List<Product> products,Collection<PrintTemplate> printTemplates ,List<PrintTempField> fields) {
        buildRecord(new ArrayList<>(orders));
        orders.forEach(order -> {
            Optional<Product> optionalProduct = products.stream().filter(p->p.getPrdCode().equals(order.getPrdCode())).findFirst();
            if(optionalProduct.isPresent()){
                Product product = optionalProduct.get();
                Integer printTempId = product.getExpressTemplate();
                PrintTemplate pt = printTemplates.stream().filter(printTemplate -> printTemplate.getId().equals(product.getExpressTemplate())).findFirst().get();
                order.setPrintTemp(pt);
                List<PrintTempField> printTempFields = fields.stream().filter(field->field.getPrintTempId().equals(printTempId)).collect(Collectors.toList());
                buildPrintTempValues(order,printTempFields);
            }
        });
    }

    private void buildPrintTempValues(Order order, List<PrintTempField> printTempFields) {
        List<TempField> finalFields = new ArrayList<>();
        printTempFields.forEach(printTempField -> {
            TempField ff = new TempField();
            BeanUtils.copyProperties(printTempField,ff);
            if (ff.getRemote().equals(1)){
                finalFields.add(fieldProcess(order,ff));
            }else{
                finalFields.add(ff);
            }
        });
        order.setPrintTempFields(finalFields);
    }

    private TempField fieldProcess(Order order,TempField ff){
        try {
            Field field = Order.class.getDeclaredField(ff.getField());
            field.setAccessible(true);
            Object value = field.get(order);
            System.out.println("属性名称:"+ff.getField()+"属性值："+value);
            if(value!=null){
                ff.setFieldValue(value.toString());
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return ff;
    }


    @Override
    public List<Order> getByAfterCodes(List<String> codes) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("after_code", codes);
        return list(queryWrapper);
    }

    @Override
    public Map<String, Integer> countOrderTotal(Integer adminId) {
        System.out.println("管理员ID" + adminId);
        List<Integer> adminIds = adminService.getChildrenIds(adminId);
        adminIds.add(adminId);
        List<CountOrder> countOrders = orderMapper.countOrder(adminIds);
        CountOrder countOrder10 = countOrders.stream().filter(countOrder -> countOrder.getState().equals(10)).findFirst().orElse(null);
        CountOrder countOrder15 = countOrders.stream().filter(countOrder -> countOrder.getState().equals(15)).findFirst().orElse(null);
        CountOrder countOrder30 = countOrders.stream().filter(countOrder -> countOrder.getState().equals(30)).findFirst().orElse(null);
        CountOrder countOrder35 = countOrders.stream().filter(countOrder -> countOrder.getState().equals(35)).findFirst().orElse(null);

        Map<String, Integer> map = new HashMap<>();
        map.put("10", countOrder10 == null ? 0 : countOrder10.getTotal());
        map.put("15", countOrder15 == null ? 0 : countOrder15.getTotal());
        map.put("30", countOrder30 == null ? 0 : countOrder30.getTotal());
        map.put("35", countOrder35 == null ? 0 : countOrder35.getTotal());
        return map;
    }

    public List<String> importOrderExcel(MultipartFile file, Integer crteMngId,String consumerCode,Integer type) throws IOException {
        ZipSecureFile.setMinInflateRatio(-1.0d);
        if(type==2) {
            OrderImportListener excelListener = new OrderImportListener(this, expressCodeService, productPriceService, iProductService, dictDataService, redisKit, crteMngId, consumerCode);
             EasyExcelFactory.readBySax(new BufferedInputStream(file.getInputStream()), new Sheet(1, 1, OrderExcelModel.class), excelListener);
            return excelListener.getErrorMsgs();
        }else{
            OrderImportListenerUSA excelListener = new OrderImportListenerUSA(this, expressCodeService, productPriceService, iProductService, dictDataService, redisKit, crteMngId, consumerCode);
            EasyExcelFactory.readBySax(new BufferedInputStream(file.getInputStream()), new Sheet(1, 1, OrderExcelModelUSA.class), excelListener);
            return excelListener.getErrorMsgs();
        }

    }

    @Override
    public Order getOrderById(Integer orderId) {
        Order order = getById(orderId);
        List<Commodity> commodities = commodityService.getListCommodityBycode(order.getCommodityCode());
        order.setCommodityList(commodities);
        return order;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveImportOrders(List<Order> orders, List<Commodity> commodities, List<OrderRecord> recodes) {
        boolean orderOk = saveBatch(orders, 500);
        boolean commodityOk = commodityService.saveBatch(commodities, 500);
        boolean recodeOK = orderRecordService.saveBatch(recodes, 500);
        orders.forEach(order -> redisKit.putHash(RedisKeyConfig.ORDER_CODE, order.getCommodityCode(), order.getCommodityCode()));
        rightCenteralPlace();
        return orderOk && commodityOk && recodeOK;
    }

    /**
     * 将订单列表改为可以导出的格式（和导入格式一样：同一个订单的不同物品另起一行）
     * @param orders
     * @return
     */
    private List<Order> buildExportOrderList(List<Order> orders, Order ord){
        List<Order> list = new ArrayList<>();

        if (orders.size() == 0) {
            return orders;
        }
        List<String> orderCodes = new ArrayList<>();
        List<String> afterCodes = new ArrayList<>();
        List<Integer> luxiangIds = new ArrayList<>();
        List<Integer> ids = new ArrayList<>();
        Map<String, Product> productMap = new HashMap<>();
        orders.forEach(order -> {
            orderCodes.add(order.getCommodityCode());
            luxiangIds.add(order.getTransportation());
            afterCodes.add(order.getAfterCode());
            ids.add(order.getId());
        });
        Map<Integer, String> afterCodeMap = new HashMap<>();
        if ("HTK_P0022".equals(ord.getPrdCode()) || "HTK_P0023".equals(ord.getPrdCode())) {
            List<Pdf> pdfList = pdfService.getPdfByOrderIds(ids);
            for (Pdf pdf : pdfList) {
                afterCodeMap.put(pdf.getOrderId(), pdf.getAfterCode());
            }
        }

        List<Commodity> commodities = commodityService.getListCommodityBycodes(orderCodes);
        List<ProductPrice> priceList = (List<ProductPrice>) this.productPriceService.listByIds(luxiangIds);
        Map<Integer, ProductPrice> priceMap = new HashMap<>();
        for (ProductPrice price : priceList) {
            priceMap.put(price.getId(), price);
        }
        for (Order order : orders) {
            String prdCode = order.getPrdCode();
            Integer transportation = order.getTransportation();
            final String commodityCode = order.getCommodityCode();
            List<Commodity> commodityList = commodities.stream().filter(commodity -> commodity.getCommodityCode().equals(commodityCode)).collect(Collectors.toList());
            order.setCommodityList(commodityList);

            if (!productMap.containsKey(prdCode)) {
                Product product = this.iProductService.getProductByCode(prdCode);
                productMap.put(prdCode, product);
            }
            if (CollectionUtils.isEmpty(commodityList)) {
                order.setTransportationName(priceMap.get(transportation) == null ? "" :
                        this.productPriceService.getProductPriceName(productMap.get(prdCode), priceMap.get(transportation)));
                list.add(order);
            } else {
                for (int i = 0; i < commodityList.size(); i++) {
                    Commodity commodity = commodityList.get(i);
                    if (i > 0) {
                        order = new Order();
                    }
                    order.setCommodityName(commodity.getCommodityName());
                    order.setCommodityValue(BigDecimal.valueOf(commodity.getCommodityValue() == null ? 0 : commodity.getCommodityValue()));
                    order.setAmount(commodity.getAmount());
                    order.setCommodityWeight(commodity.getWeight() + "");
                    order.setTransportationName(priceMap.get(transportation) == null ? "" :
                            this.productPriceService.getProductPriceName(productMap.get(prdCode), priceMap.get(transportation)));
                    if ("HTK_P0022".equals(ord.getPrdCode()) || "HTK_P0023".equals(ord.getPrdCode())) {
                        order.setPostCode(afterCodeMap.get(order.getId()));
                    }
                    list.add(order);
                }
            }
        }
        return list;
    }

}

